package com.kob.backend.service.impl.auction;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.kob.backend.dto.AuctionDto;
import com.kob.backend.mapper.AuctionMapper;
import com.kob.backend.pojo.Auction;
import com.kob.backend.pojo.AuctionTask;
import com.kob.backend.pojo.DefaultTask;
import com.kob.backend.pojo.TaskObj;
import com.kob.backend.service.auction.AuctionService;
import com.kob.backend.service.auction.AuctionTaskService;
import com.kob.backend.service.auction.DefaultTaskService;
import com.kob.backend.service.impl.utils.CommonUtils;
import com.kob.backend.utils.kkt.Market;
import com.kob.backend.vo.AuctionTaskVo;
import jakarta.annotation.Resource;
import lombok.SneakyThrows;
import org.springframework.stereotype.Service;

import java.text.DecimalFormat;
import java.util.*;

/**
 * <pre>{@code
 *
 * }</pre>
 *
 * @author Summerday
 * @date 2023/3/17
 */
@Service
public class AuctionServiceImpl extends ServiceImpl<AuctionMapper, Auction> implements AuctionService {
    @Resource
    AuctionMapper auctionMapper;

    @Resource
    AuctionTaskService auctionTaskService;

    @Resource
    DefaultTaskService defaultTaskService;

    @Override
    public Auction getAuctionById(Integer id) {
        return auctionMapper.selectOne(new QueryWrapper<Auction>().eq("id", id));
    }

    private List<Integer> splitString2List(String s) {
        List<Integer> res = new ArrayList<>();
        if(s == null || s.length() == 0) return res;
        String[] split = s.split(",");
        for(String cur : split) {
            res.add(Integer.valueOf(cur));
        }
        return res;
    }

    private List<List<Integer>> splitString2Cost(String s) {
        List<List<Integer>> ans = new ArrayList<>();
        String[] split = s.split("\\|");
        System.out.println(Arrays.toString(split));
        for(String value : split) {
            ans.add(splitString2List(value));
        }
        return ans;
    }


    @Override
    // rsuid -> [(propertyname val, cost), (),()]
    public Map<Integer, List<TaskObj>> Auction2TaskMapping(Auction auction) {
        Map<Integer, List<TaskObj>> ans = new HashMap<>();
        // rsuIDs
        List<Integer> rsus = splitString2List(auction.getRsu());
        List<Integer> taskIds = splitString2List(auction.getTaskId());

        List<List<Integer>> costs = splitString2Cost(auction.getPropertyValue());
        for(int i = 0; i < rsus.size(); i++) {

            // 当前的rsu的任务的视图
            DefaultTask defaultTask = defaultTaskService.getById(taskIds.get(i));
            String propertyList = defaultTask.getPropertyList();
            List<String> proList = CommonUtils.split(propertyList);
            List<String> costList = CommonUtils.split(defaultTask.getCostList());

            List<TaskObj> taskObjs = new ArrayList<>();
            for(int j = 0; j < proList.size(); j++) {
                TaskObj taskObj = new TaskObj();
                taskObj.setPropertyName(proList.get(j));
                taskObj.setPropertyCost(Integer.valueOf(costList.get(j)));
                taskObj.setPropertyValue(costs.get(i).get(j));
                taskObj.setTaskId(String.valueOf(taskIds.get(i)));
                taskObj.setTaskName(defaultTask.getTaskName());
                taskObjs.add(taskObj);
            }
            ans.put(rsus.get(i), taskObjs);

        }
        return ans;
    }

    @SneakyThrows
    @Override
    public Map<String, Object> startIDA(Integer id){
        Map<String, Object> res = new HashMap<>();

        // 获得拍卖双方信息
        Auction auction = getAuctionById(id);
        Map<Integer, List<TaskObj>> taskMap = Auction2TaskMapping(auction);

        // 获得每个rsu对应的任务，以及消费
        String ev = auction.getEv();
        String rsu = auction.getRsu();

        Map<Integer, Integer> evMap = new HashMap<>();
        Map<Integer, Integer> rsuMap = new HashMap<>();
        List<Integer> evs = splitString2List(ev);
        List<Integer> rsus = splitString2List(rsu);
        int i = 1;
        for(int e : evs) {
            evMap.put(i++, e);
        }
        i = 1;
        for(int r : rsus) {
            rsuMap.put(i++, r);
        }
        // 进行双边拍卖
        int M = rsus.size();
        int N = evs.size();

        Market market = new Market(M, N);
        market.IDA();

        // 迭代次数
        int totalTime = market.getT();

        double[][] pRsuJ = market.getPRsuJ();
        double[][] qEvI = market.getQEvI();
        DecimalFormat df = new DecimalFormat("#.##");

        // 封装任务列表
        List<AuctionTask> auctionTasks = new ArrayList<>();
        for(int m = 1; m <= M; m++) {
            for(int n = 1; n <= N; n++) {
                if(pRsuJ[m][n] > qEvI[n][m]) {
                    AuctionTask auctionTask = new AuctionTask();
                    auctionTask.setAuctionId(id);
                    auctionTask.setPublishTime(new Date());
                    auctionTask.setRsuToEv(df.format(pRsuJ[m][n]));
                    auctionTask.setEvToRsu(df.format(qEvI[n][m]));
                    auctionTask.setEv(evMap.get(n));
                    Integer rsuId = rsuMap.get(m);
                    auctionTask.setRsu(rsuId);
                    List<TaskObj> taskObjs = taskMap.get(rsuId);
                    auctionTask.setTaskId(taskObjs.get(0).getTaskId());
                    auctionTask.setDescription(taskObjs.get(0).getTaskName());
                    ObjectMapper objectMapper = new ObjectMapper();
                    String tasks = objectMapper.writeValueAsString(taskObjs);
                    System.out.println(tasks);
                    auctionTask.setTasks(tasks);
                    auctionTasks.add(auctionTask);
                }
            }
        }
        if(auctionTasks.size() == 0) {
            res.put("msg", "本次拍卖失败");
            return res;
        }
        // 先删掉当前拍卖的信息
        auctionTaskService.deleteByAuctionId(id);
        // 记录当前拍卖完成任务信息
        auctionTaskService.saveBatch(auctionTasks);

        List<AuctionTaskVo> vos = new ArrayList<>();
        auctionTasks.forEach(auctionTask -> {
            vos.add(AT2VO(auctionTask));
        });

        res.put("auction_task", vos);
        res.put("total_time", totalTime);
        return res;
    }

    @SneakyThrows
    private AuctionTaskVo AT2VO(AuctionTask task) {
        AuctionTaskVo vo = new AuctionTaskVo();
        vo.setAuctionId(task.getAuctionId());
        vo.setDescription(task.getDescription());
        vo.setEndTime(task.getEndTime());
        vo.setEv(task.getEv());
        vo.setTaskId(task.getTaskId());
        vo.setId(task.getId());
        String tasks = task.getTasks();
        ObjectMapper objectMapper = new ObjectMapper();
        List<TaskObj> taskObjs = objectMapper.readValue(tasks,
                objectMapper.getTypeFactory().constructCollectionType(List.class, TaskObj.class));
        double cost = 0;
        for(TaskObj taskObj : taskObjs) {
            // 计算能量消耗
            cost += taskObj.getPropertyCost() * taskObj.getPropertyValue();
            if(cost > 100) {
                cost = 100;
                break;
            }
        }
        vo.setCost(String.valueOf(cost));
        vo.setTasks(taskObjs);
        vo.setEvToRsu(task.getEvToRsu());
        vo.setRsuToEv(task.getRsuToEv());
        vo.setPublishTime(task.getPublishTime());
        vo.setRsu(task.getRsu());
        return vo;
    }
    @Override
    public Auction register(AuctionDto auctionDto) {
        Auction auction = new Auction();
        auction.setAdmin(auctionDto.getAdmin());
        auction.setDescription(auctionDto.getDescription());
        auction.setEv(auctionDto.getEv());
        auction.setRsu(auctionDto.getRsu());
        auction.setPublishTime(new Date());
        auction.setTaskId(auctionDto.getTaskId());
        auction.setPropertyValue(auctionDto.getPropertyValue());
        this.save(auction);
        return auction;
    }
}
